use std::env;
use std::path::PathBuf;

use config::{Config as ConfigStub, ConfigError, File};
use once_cell::sync::Lazy;
use serde::Deserialize;

static CONFIG_PATH: Lazy<PathBuf> = Lazy::new(|| get_config_path().unwrap());
pub static CONFIG: Lazy<Config> = Lazy::new(|| {
    Config::new().unwrap_or_else(|err| {
        println!("config init err:{}, using default.", err);
        Config::default()
    })
});

pub fn init() -> &'static Config {
    Lazy::force(&CONFIG)
}

#[derive(Default, Debug, Deserialize)]
pub struct Config {
    pub node: Node,
    pub server: Server,
    pub log: Log,
}

impl Config {
    fn new() -> Result<Self, ConfigError> {
        let builder = ConfigStub::builder().add_source(File::with_name(
            CONFIG_PATH.join("Server").to_str().unwrap(),
        ));
        builder.build()?.try_deserialize::<Self>()
    }
}

#[derive(Debug, Deserialize)]
pub struct Node {
    pub node_type: String,
    pub node_name: String,
}

impl Default for Node {
    fn default() -> Self {
        Self {
            node_type: "room".into(),
            node_name: "room1".into(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Server {
    pub daemon: bool,
    pub listen_port: u16,
    pub etcd_endpoints: Vec<String>,
}

impl Default for Server {
    fn default() -> Self {
        Self {
            daemon: false,
            listen_port: 6290,
            etcd_endpoints: vec!["127.0.0.1:2379".into()],
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Log {
    pub file_path: String,
    pub level: String,
}

impl Default for Log {
    fn default() -> Self {
        Self {
            file_path: "/tmp/honeybee-usc.log".into(),
            level: "trace".into(),
        }
    }
}

fn get_config_path() -> Option<PathBuf> {
    //1.命令行参数
    let path = env::args()
        .find(|arg| arg.starts_with("config_dir="))
        .map(|arg| arg.split('=').last().map(PathBuf::from).unwrap());
    if path.is_some() && path.as_ref().unwrap().exists() {
        return path;
    }

    //2.执行程序所在路径
    let path = env::current_exe()
        .ok()
        .as_ref()
        .and_then(|path| path.parent())
        .map(|path| path.join("config"));
    if path.is_some() && path.as_ref().unwrap().exists() {
        return path;
    }

    //3.执行程序所在路径上一层
    let path = env::current_exe()
        .ok()
        .as_ref()
        .and_then(|path| path.parent())
        .and_then(|path| path.parent())
        .map(|path| path.join("config"));
    if path.is_some() && path.as_ref().unwrap().exists() {
        return path;
    }

    //4.运行程序所在路径
    let path = env::current_dir()
        .ok()
        .as_ref()
        .map(|path| path.join("config"));
    if path.is_some() && path.as_ref().unwrap().exists() {
        return path;
    }

    //5.运行程序所在路径上一层
    let path = env::current_dir()
        .ok()
        .as_ref()
        .and_then(|path| path.parent())
        .map(|path| path.join("config"));
    if path.is_some() && path.as_ref().unwrap().exists() {
        return path;
    }

    //6.运行程序所在路径下一层执行程序名所在路径
    let path = env::current_dir().ok().as_ref().and_then(|path| {
        env::current_exe()
            .ok()
            .as_ref()
            .and_then(|exe_path| exe_path.file_stem())
            .map(|exe_name| path.join(exe_name).join("config"))
    });
    if path.is_some() && path.as_ref().unwrap().exists() {
        return path;
    }
    None
}
